/* 
 * Enterprise Library Extensions - DI + ORM.
 * Copyright (C) 2006
 *
 * GNU General Public License
 *
 * This program is free software; you can redistribute 
 * it and/or modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation; either version 2 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 */
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Text;
using ELE.Common.Util;

namespace ELE.EnterpriseLibrary.Naming
{
	/// <summary>
  /// This class represents a composite name -- a sequence of component names spanning multiple namespaces. 
  /// Each component is a string name from the namespace of a naming system. If the component comes from a 
  /// hierarchical namespace, that component can be further parsed into its atomic parts by using the 
  /// CompoundName class. 
  /// The components of a composite name are numbered. The indexes of a composite name with N components 
  /// range from 0 up to, but not including, N. This range may be written as [0,N). The most significant 
  /// component is at index 0. An empty composite name has no components. 
  /// </summary>
  [Serializable]
	public class CompositeName : IName, ICloneable
	{
    private StringCollection mComponents;
    /// <summary>
    /// The name delimiter to separate components
    /// </summary>
    public const string NAME_DELIMITER = StringUtils.SLASH_BACK;
    /// <summary>
    /// Initializes the name
    /// </summary>
    protected void Init()
    {
      mComponents = new StringCollection();
    }
    /// <summary>
    /// Constructs an empty name
    /// </summary>
		public CompositeName()
		{
      Init();
		}
    /// <summary>
    /// Constructs a name based on the given collection of components
    /// </summary>
    /// <param name="components">the initial components</param>
    public CompositeName(StringCollection components)
    {
      Init();
      if(components != null)
      {
        foreach(string name in components)
        {
          mComponents.Add(name);
        }
      }
    }
    /// <summary>
    /// Constructs a name with an initial name string
    /// </summary>
    /// <param name="name">the name</param>
    public CompositeName(string name)
    {
      Init();
      if(name != null)
      {
        ((StringCollection)mComponents).AddRange(name.Split(NAME_DELIMITER.ToCharArray()));
      }
    }
    #region IName Members
    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pPosition"></param>
    /// <param name="pComponent"></param>
    /// <returns></returns>
    public IName Add(int pPosition, string pComponent)
    {
      if(pComponent == null)
      {
        throw new NamingException("Argument pComponent in Add method call of CompositeName must not be null");
      }
      string[] subComponents = pComponent.Split(NAME_DELIMITER.ToCharArray());
      if(mComponents.Count <= pPosition)
      {
        int iCount = mComponents.Count;
        for(int i = 0; i < pPosition - iCount; i++)
        {
          mComponents.Add("");
        }
        ((StringCollection)mComponents).AddRange(subComponents);
      }
      else
      { 
        for(int i = 0; i < subComponents.Length; i++)
        {
          ((StringCollection)mComponents).Insert(pPosition + i, subComponents[i]);
        }
      }
      return this;
    }

    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pComponent"></param>
    /// <returns></returns>
    public IName Add(string pComponent)
    {
      return Add(mComponents.Count, pComponent);
    }

    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pPosition"></param>
    /// <param name="pName"></param>
    /// <returns></returns>
    public IName AddAll(int pPosition, IName pName)
    {
      if(pName == null)
      {
        throw new NamingException("Argument pName in AddAll method call of CompositeName must not be null");
      }
      StringCollection allNames = pName.GetAll();
      StringBuilder composedName = new StringBuilder();
      foreach(string name in allNames)
      {
        composedName.Append(name).Append(NAME_DELIMITER);
      }
      composedName.Remove(composedName.Length - 1, 1);
      return Add(pPosition, composedName.ToString());
    }

    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pName"></param>
    /// <returns></returns>
    public IName AddAll(IName pName)
    {
      return AddAll(mComponents.Count, pName);
    }

    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pObject"></param>
    /// <returns></returns>
    public int CompareTo(object pObject)
    {
      if(pObject == null || !(pObject is IName))
      {
        throw new NamingException("Argument pObject in CompareTo method call of CompositeName must not be null and must be of type IName");
      }
      StringCollection objColl = ((IName)pObject).GetAll();
      
      return this.ToString().CompareTo(this.ToString(objColl));
    }

    
    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pName"></param>
    /// <returns></returns>
    public bool EndsWith(IName pName)
    {
      if(pName == null)
      {
        throw new NamingException("Argument pName in EndsWith method call of CompositeName must not be null");
      }
      StringCollection objColl = pName.GetAll();
      StringCollection myColl = GetAll();
      if(objColl.Count > myColl.Count)
      {
        return false;
      }
      int diff = myColl.Count - objColl.Count;
      for(int i = 0; i < objColl.Count; i++)
      {
        if(!objColl[i].Equals(myColl[i + diff]))
        {
          return false;
        }
      }
      return true;
    }

    
    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pName"></param>
    /// <returns></returns>
    public bool StartsWith(IName pName)
    {
      if(pName == null)
      {
        throw new NamingException("Argument pName in StartsWith method call of CompositeName must not be null");
      }
      StringCollection objColl = pName.GetAll();
      StringCollection myColl = GetAll();
      if(objColl.Count > myColl.Count)
      {
        return false;
      }
      for(int i = 0; i < objColl.Count; i++)
      {
        if(!objColl[i].Equals(myColl[i]))
        {
          return false;
        }
      }
      return true;
    }

    
    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pPosition"></param>
    /// <returns></returns>
    public string Get(int pPosition)
    {
      if(mComponents.Count <= pPosition)
      {
        return null;
      }
      return mComponents[pPosition];
    }

    
    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <returns></returns>
    public StringCollection GetAll()
    {
      return mComponents;
    }

    
    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pPosition"></param>
    /// <returns></returns>
    public IName GetPrefix(int pPosition)
    {
      if(pPosition >= mComponents.Count || pPosition < 0)
      {
        return null;
      }
      string[] copy = new string[pPosition + 1];
      mComponents.CopyTo(copy, 0);
      StringCollection col = new StringCollection();
      for(int i = 0; i <= pPosition; i++)
      {
        col.Add(copy[i]);
      }
      return new CompositeName(col);
    }

    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pPosition"></param>
    /// <returns></returns>
    public IName GetSuffix(int pPosition)
    {
      if(pPosition >= mComponents.Count || pPosition < 0)
      {
        return null;
      }
      string[] copy = new string[mComponents.Count - pPosition];
      mComponents.CopyTo(copy, 0);
      StringCollection col = new StringCollection();

      for(int i = 0; i < mComponents.Count - pPosition; i++)
      {
        col.Add(copy[i + pPosition]);
      }
      return new CompositeName(col);
    }

    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    public bool IsEmpty
    {
      get
      {
        if(mComponents == null || mComponents.Count <= 0)
        {
          return true;
        }
        return false;
      }
    }

    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    /// <param name="pPosition"></param>
    /// <returns></returns>
    public object Remove(int pPosition)
    {
      if(pPosition >= mComponents.Count)
      {
        return null;
      }
      string copy = mComponents[pPosition];
      mComponents.RemoveAt(pPosition);
      return copy;
    }
    /// <summary>
    /// Get a string version of a stringcollection based on the rules of compositenames.
    /// </summary>
    /// <param name="names"></param>
    /// <returns></returns>
    public string ToString(StringCollection names)
    {
      if(names == null) return "";
      StringBuilder namesStr = new StringBuilder();
      string div = "";
      foreach(string name in names)
      {
        namesStr.Append(div).Append(name);
        div = NAME_DELIMITER;
      }
      return namesStr.ToString();
    }
    /// <summary>
    /// Get a string representation of this compositename
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
      return ToString(this.GetAll());
    }
    /// <summary>
    /// Implementation of <see cref="IName"/> Interface's method
    /// </summary>
    public int Size
    {
      get
      {
        return mComponents.Count;
      }
    }

    #endregion

    #region ICloneable Members

    /// <summary>
    /// Implementation of <see cref="ICloneable"/> Interface's method
    /// </summary>
    /// <returns></returns>
    public object Clone()
    {
      string[] colStr = new string[mComponents.Count];
      mComponents.CopyTo(colStr, 0);
      StringCollection col = new StringCollection();
      col.AddRange(colStr);
      return new CompositeName(col);
    }

    #endregion
  }
}
